package cn.gem.rainbow.cfg.web.interceptor;

import cn.gem.rainbow.cfg.restful.APIException;
import cn.gem.rainbow.cfg.restful.ResultCodeEnum;
import cn.gem.rainbow.pojo.entity.SysUser;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 *
 *
 * 拦截器只拦截 请求，不拦截 响应结果,
 * 且拦截器是在 过滤器 (过滤完 request请求 )后，才执行
 *
 * filter1 进--> filter2 进
 *        ---> interceptor 进---> interceptor 出
 *          ---> filter2出----> filter1 出
 */
@Log4j2
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandle里面.....");

        log.info("-------"+request.getRequestURI());

        String frontTokenStr = request.getHeader("Authorization");
        log.info("frontTokenStr: {}",frontTokenStr);
//        //请求头里没有token,就不进入Controller
        if (StringUtils.isEmpty(frontTokenStr)){
            log.error("请求头里没有token");
            throw new APIException(ResultCodeEnum.TOKEN_NULL);
        }

        Subject subject = SecurityUtils.getSubject();
        String tokenRedis = stringRedisTemplate.opsForValue().get((String)subject.getPrincipal());
        if (StringUtils.isEmpty(tokenRedis)){
            //页面重新登录，应先调用/logout清掉shiro会话,再调/login生成新会话和token
            throw new APIException(ResultCodeEnum.TOKEN_TIME_OUT);
        }
        if (!StringUtils.equals("Bearer "+tokenRedis,frontTokenStr)){

            //当前用户已登录，且token未过期;此时用新token请求，则不返回数据，要求退出重登
            //即1个用户在登录后仅可有1个有效token;用其他token，则视为过期，要求重登
            //有效避免多人在不同浏览器登录同一个账号
            throw new APIException(ResultCodeEnum.TOKEN_USER_ALREADY_SIGN);
        }


        //此处可以增加判断 token是否和redis里的一致（根据userId查询redis token,不一致则请求失败）,以及token解析超时
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle 里面.....");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion 里面.....");

    }
}
